/*
 * WDropDown.java
 *
 * Created on 4 November 2007, 22:46
 *
 */

package net.ubinow.mflex.widgets;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

import net.ubinow.mflex.baseui.AbsWidget;
import net.ubinow.mflex.baseui.WFont;
import net.ubinow.mflex.data.IDataItem;
import net.ubinow.mflex.data.SimpleDataItem;
import net.ubinow.mflex.events.Event;
import net.ubinow.mflex.util.Constants;
import net.ubinow.mflex.util.MiscUtil;

/**
 * dropdown selection widget; provides a list of options to the user where the user can access this list
 * by clicking on the widget to expand the widget thus showing the available options.
 * panel here describes the dropdown selection list available.
 * @author Josh
 */
public class WDropDown extends AbsWidget {
    
    private static final int STATE_COLLAPSED    = 0;
    private static final int STATE_EXPAND       = 1;
    
    private int _currentState = STATE_COLLAPSED;
    
    private Image _imgNormal = null;
    private Image _imgSelected = null;
    private Image _imgPanel = null;
    private Image _imgHighlight = null;
    
    // panel attributes
    private int _panelWidth = 0;
    private int _panelHeight = 0;
    private int _panelX = 0;
    private int _panelY = 0;
    private int _tY = 0; // remember the 'true' y position so we can accurately test the bounds for this control
    private int _panelCurHeight = 0; // panels current height (used for the animating expanding panel)
    private int _panelItemGap = Constants.AD_ITEM_GAP;
    
    private int _textPaddingX = Constants.AD_TEXT_PADDING_X; // horizontal padding of the component
    private int _textPaddingY = Constants.AD_TEXT_PADDING_Y; // vertical padding of the component
    
    private int _panelPaddingX = Constants.AD_DROPDOWN_PANEL_PADDING_X;
    private int _panelPaddingY = Constants.AD_DROPDOWN_PANEL_PADDING_Y;
    
    private int _textAlignment = Constants.ALIGN_CENTRE_H | Constants.ALIGN_CENTRE_V;
    private int _textX = -1; // position for the text
    private int _textY = -1;
    
    private int _tmpSelectedIndex = -1;
    
    private int _viewableHeight = 0; // this is the actual screen realestate that we can use, require this as we need to calculate if the expanded panel is off the screen // TODO: make this accessable from the container ie widgets hold a reference to their container
    
    private MiscUtil _miscUtils = null;
    
    /** the number of items displayed at once when expanded **/ 
    private int _itemsToShow = Constants.AD_DEFAULT_DROPDOWN_DISPLAY_NUMBER;
    
    /** Creates a new instance of WDropDown */
    public WDropDown( Image normal, Image selected, Image panel, Image highlight, WFont font, int viewableHeight ) {
        this( Constants.UNDEFINED, normal, selected, panel, highlight, font, viewableHeight );
        
    }
    
    public WDropDown( String id, Image normal, Image selected, Image panel, Image highlight, WFont font, int viewableHeight ) {
        _id = id;
        _imgNormal = normal;
        _imgSelected = selected;
        _imgPanel = panel;
        _imgHighlight = highlight;
        _font = font;
        _viewableHeight = viewableHeight;               
        
        init();
        
    }
    
    private void init(){
        _currentState = STATE_COLLAPSED;
        _panelCurHeight = 0;
        
        _textAlignment = Constants.ALIGN_CENTRE_V | Constants.ALIGN_CENTRE_H;
        
        if( _imgNormal != null ){
            _width = _imgNormal.getWidth();
            _height = _imgNormal.getHeight();
        }
        
        _miscUtils = MiscUtil.getInstance();
        _tmpSelectedIndex = -1;
    }
    
    //<editor-fold defaultstate="collapsed" desc="overrides">
    
    public void addItem( IDataItem item ){
        super.addItem( item );
    }
    
    public void removeItem( IDataItem item ){
        super.removeItem( item );
    }
    
    public void insertItem(int index, IDataItem item) {
        super.insertItem( index, item );
    }
    
    public void setItems( IDataItem[] items ){
        super.setItems( items );
    }
    
    /** first layer component draws the actual component; next layer draws the panel when it is open **/ 
    public int maxLayers(){
        return 2;         
    }
    
    /**
     * sets the currently selected item
     * @param index: index of the selected item in the _items array
     **/
    public void setIndex( int index ){
        super.setIndex( index );
        _textX = -1;
    }
    
    public void setX( int x ){
        _textX = -1;
        super.setX( x );
    }
    
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="private methods">
    
    private void expand(){
        recalcPanelPosition();
        _currentState = STATE_EXPAND;
        
        // set the temp selected index - used to highlight of the currently selected item when the dropdown is expanded 
        _tmpSelectedIndex = _selectedIndex;
    }
    
    private void collapse(){
        _currentState = STATE_COLLAPSED;        
    }
    
    private boolean isExpanded(){
        return (_currentState == STATE_EXPAND && _panelCurHeight == _panelHeight );
    }
    
    private boolean isCollapsed(){
        return (_currentState == STATE_COLLAPSED && _panelCurHeight == 0);
    }
    
    private void realignTextX(){
        // work out text position x
        if( (_textAlignment & Constants.ALIGN_LEFT) == Constants.ALIGN_LEFT ){
            _textX = _x+_textPaddingX;
        } else if( (_textAlignment & Constants.ALIGN_RIGHT) == Constants.ALIGN_RIGHT ){
            _textX = _x-_textPaddingX+(_width-_font.stringWidth( getSelectedText() ) );
        } else if( (_textAlignment & Constants.ALIGN_CENTRE_H) == Constants.ALIGN_CENTRE_H ){
            _textX = _x + (_width-_font.stringWidth( getSelectedText())>>1);
        }
    }
    
    private void realignTextY(){
        // work out text position x
        if( (_textAlignment & Constants.ALIGN_TOP) == Constants.ALIGN_TOP ){
            _textY = _y+_textPaddingY;
        } else if( (_textAlignment & Constants.ALIGN_CENTRE_V) == Constants.ALIGN_CENTRE_V ){
            _textY = _y + ((_height-_font.getHeight())>>1);
        } else if( (_textAlignment & Constants.ALIGN_BOTTOM) == Constants.ALIGN_BOTTOM ){
            _textY = _y+_height-_textPaddingY-_font.getHeight();
        }
    }
    
    /**
     * re-calculates the panel variables (width, height, x and y positions). normally called when the
     * dataitem array has changed
     **/
    private void recalcPanelPosition(){
        
        if( _itemsToShow == -1 || _itemsToShow >= _itemsCount )
            _panelHeight = (_itemsCount)*(_font.getHeight()+_panelItemGap)+_panelItemGap;
        else 
            _panelHeight = (_itemsToShow)*(_font.getHeight()+_panelItemGap)+_panelItemGap;
        
        _panelWidth = _imgNormal.getWidth();
        _panelX = _x;
        _panelY = _y - _textPaddingY;
               
        // if the position and height of the panel is off the bottom of the screen then readjust so that it
        // is back on the screen
        if( (_tY + _panelHeight) > _viewableHeight ){
            int diff = (_tY + _panelHeight) - _viewableHeight;
            
            SimpleDataItem obj = new SimpleDataItem( Integer.toString( diff ) ) ;
            
            notifySubscribers( getEvet( Event.EVT_GUI_OUT_OF_BOUNDS, obj ) ); 
        }
        
        _panelCurHeight = 0;
    }
    
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="AbsWidget methods">
    
    protected void setWidgetType() {
        _type = Constants.WIDGET_TYPE_DROPDOWN;
    }
    
    public void setBG(Image bg) {
    }
    
    public void setBG(int colour) {
    }
    
    public void cycle() {
        
        if( _currentState == STATE_EXPAND && !isExpanded() ){
            System.err.println("panel height " + _panelHeight + ", panel cur height " + _panelCurHeight );
            _panelCurHeight += MiscUtil.getInstance().calcHalfDistance( _panelHeight, _panelCurHeight );
            System.err.println("panel current height = " + _panelCurHeight );
            if( _panelCurHeight > _panelHeight ){
                _panelCurHeight = _panelHeight;
                System.err.println("sdfsdhflsjdflksj flksdjflksjdflksdfklsdf");
            }
        } else if( _currentState == STATE_COLLAPSED && !isCollapsed() ){
            _panelCurHeight += MiscUtil.getInstance().calcHalfDistance( 0, _panelCurHeight );
            
            if( _panelCurHeight < 0 )
                _panelCurHeight = 0;
        }
        
        if( !_focus && isExpanded() ){
            collapse();
        }
    }        
    
    public void paint(Graphics g, int offsetX, int offsetY, int layer) {
        if( !_isVisible )
            return;
        
        // remember the true position 
        _tY = _y+offsetY;
        
        // realign text
        if( _textX == -1 ){
            realignTextX();
        }
        
        if( _textY == -1 ){
            realignTextY();
        }
        
        if( _focus ){
            g.drawImage( _imgSelected, _x + offsetX, _y + offsetY, Constants.GFX_ALIGN_TOP_LEFT );
        } else{
            g.drawImage( _imgNormal, _x + offsetX, _y + offsetY, Constants.GFX_ALIGN_TOP_LEFT );
        }
        
        if( isCollapsed() ){
            //TODO: draw selected text
            if( _itemsCount > 0 ){
                _font.drawString( g, getSelectedItem().getText(), _textX + offsetX, _textY + offsetY );
            }
        } else if( layer == 2 ){
            paintPanel( g, offsetX, offsetY );
        }
    }
    
    /** draw layer 1 graphics **/
    private void paintPanel( Graphics g, int offsetX, int offsetY ){
        
        int panelStartX = _x + _panelPaddingX + offsetX;
        int panelEndX = _x + _panelPaddingX + offsetX + _imgPanel.getWidth();
        int panelStartY = 27 + _y + _panelPaddingY + offsetY;
        int panelEndY = 27 + _y + _panelPaddingY + offsetY + _panelCurHeight;
        
        int itemHeight = _font.getHeight() + _panelItemGap;
        int itemWidth = panelEndX-panelStartX;
        
        // draw panel        
        _miscUtils.drawImageByTiling( g, _imgPanel, panelStartX, panelEndX,
                panelStartY, panelEndY );        
        
        
        if( _itemsCount > 0 ){
            // draw the selected on in the box        
            _font.drawString( g, _items[_tmpSelectedIndex].getText(), _textX + offsetX, _textY + offsetY );

            // TODO: draw options

            int tmpYPos = _panelItemGap + 27 + _y + _panelPaddingY + offsetY; 

            int count = _itemsToShow;
            
            if( _itemsToShow == -1 || _itemsToShow >= _itemsCount )
                    count = _itemsCount;
            
            int idx = Math.max( _tmpSelectedIndex - 1, 0 );
           
            for( int i=0; i<count; i++ ){
                // if the current y position is greater than the bottom of the current panel then break out of this loop 
                if( tmpYPos+_font.getHeight() > panelEndY )
                    break;

                // draw highlight if the current index is the seleted one
                if( idx == _tmpSelectedIndex ){                    
                    g.setColor( Constants.AD_COLOUR_HIGHLIGHT );
                    g.fillRect(  panelStartX + Constants.AD_HIGHLIGHT_PADDING_X, 
                            panelStartY + (i*itemHeight+_panelItemGap) - Constants.AD_HIGHLIGHT_PADDING_Y, 
                            itemWidth-(Constants.AD_HIGHLIGHT_PADDING_X<<1), itemHeight );
                }
                
                _font.drawString( g, _items[idx].getText(), _textX + offsetX, tmpYPos );

                tmpYPos += _panelItemGap + _font.getHeight();
                idx++;
                
                if( idx >= _itemsCount )
                    break;
            }

        }                                
    }
    
    public boolean handleKeyPressed(int action, int keyCode) {
        
        if( isCollapsed() ){
            if( action == Canvas.FIRE ){
                expand();
                return true;
            }
        } else if( isExpanded() ){
            if( action == Canvas.UP ){
                _tmpSelectedIndex--; 
                
                if( _tmpSelectedIndex < 0 )
                    _tmpSelectedIndex = _itemsCount-1;                
                
                return true;
            } else if( action == Canvas.DOWN ){
                _tmpSelectedIndex++; 
                
                if( _tmpSelectedIndex >= _itemsCount )
                    _tmpSelectedIndex = 0;
                
                return true;
            } else if( action == Canvas.FIRE ){
                collapse();
                
                if( _tmpSelectedIndex != _selectedIndex )
                    setIndex( _tmpSelectedIndex );                                
                return true;
            }
            
        }
        return false;
    }
    
    public boolean handleKeyReleased(int action, int keyCode) {
        return false;
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="wdropdown methods">
    
    /** 
     * sets the number of items that will be shown at once when expanded 
     * param itemsToShow: number of items to show (set to -1 to show all items at once)
     **/ 
    public void setNoItemToShow( int itemsToShow ){
       _itemsToShow = itemsToShow;
    }
    
    /** set the text alignment **/
    public void setAlignment( int alignment ){
        _textAlignment = alignment;
        
        // reset positioning
        _textX = _textY = -1;
    }
    
    //</editor-fold>
}
